package com.atguigu.gmall.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.dao.SearchDao;
import com.atguigu.gmall.model.list.*;
import com.atguigu.gmall.model.product.BaseCategoryView;
import com.atguigu.gmall.model.product.BaseTrademark;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.atguigu.gmall.service.SearchService;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.util.*;

@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private SearchDao searchDao;

    @Autowired
    @Qualifier("redis")
    private RedisTemplate redisTemplate;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 商品上架
     * @param skuId
     */
    public void upperGoods(Long skuId) {
        Goods goods = new Goods();
        //1.添加sku信息
        SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
        goods.setId(skuId);
        goods.setDefaultImg(skuInfo.getSkuDefaultImg());
        goods.setTitle(skuInfo.getSkuName());
        goods.setPrice(skuInfo.getPrice().doubleValue());
        goods.setCreateTime(new Date());
        goods.setTmId(skuInfo.getTmId());
        //2.查询品牌信息
        BaseTrademark trademark = productFeignClient.baseTrademarkById(skuInfo.getTmId());
        goods.setTmName(trademark.getTmName());
        goods.setTmLogoUrl(trademark.getLogoUrl());
        //3.一二三及分类
        BaseCategoryView baseCategoryView = productFeignClient.getBaseCategoryView(skuInfo.getCategory3Id());
        BeanUtils.copyProperties(baseCategoryView,goods,"id");
        goods.setAttrs(productFeignClient.getSearchAttrList(skuId));
        searchDao.save(goods);

    }

    /**
     * 商品下架
     * @param skuId
     */
    public void lowerGoods(Long skuId) {
                searchDao.deleteById(skuId);
    }

    /**
     *
     * @param skuId
     */
    public void addHotScore(Long skuId) {

        Double hotScore = redisTemplate.opsForZSet().incrementScore("hotScore", "skuId:" + skuId, 1);
        if(hotScore%10==0){
            Optional<Goods> goodsById = searchDao.findById(skuId);
            Goods goods = goodsById.get();
            goods.setHotScore(hotScore.longValue());
            searchDao.save(goods);
        }
    }

    /**
     * 搜索
     * @param searchParam
     * @return
     */
    public SearchResponseVo getSearchList(SearchParam searchParam) {
        //1.构建搜索对象

        SearchRequest searchRequest = buildSearchRequest(searchParam);
        SearchResponse searchResponse = null;
        //2.执行搜索
        try {

             searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        } catch (IOException e) {
            e.printStackTrace();
        }
        SearchHit[] hits = searchResponse.getHits().getHits();

        //3.解析结果
        SearchResponseVo responseVo = parseSearchResponse(searchResponse);
        Integer pageNo = searchParam.getPageNo();
        Integer pageSize = searchParam.getPageSize();
        Long total = responseVo.getTotal();
        responseVo.setPageNo(pageNo);
        responseVo.setPageSize(pageSize);
        long totalPages = total%pageSize==0?total/pageSize:total/pageSize+1;
        responseVo.setTotalPages(totalPages);
        return responseVo;
    }
    //解析结果
    private SearchResponseVo parseSearchResponse(SearchResponse searchResponse) {
        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHits = hits.getHits();
        SearchResponseVo responseVo = new SearchResponseVo();
        List<Goods> goodsList = new ArrayList<>();
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            Goods goods = JSONObject.parseObject(sourceAsString, Goods.class);
            //解析高亮结果
            Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
            if(highlightFields!=null){
                HighlightField  highlightField = highlightFields.get("title");
                Text[] fragments = highlightField.getFragments();
                for (Text fragment : fragments) {
                    goods.setTitle(fragment.toString());
                }
            }
            goodsList.add(goods);
        }
        //解析品牌聚合结果
        List<SearchResponseTmVo> responseTmVos = new ArrayList<>();
        Aggregations responseAggregations = searchResponse.getAggregations();
        ParsedLongTerms aggregation = responseAggregations.get("tmIdAgg");
        List<ParsedLongTerms.ParsedBucket> buckets = (List<ParsedLongTerms.ParsedBucket>) aggregation.getBuckets();
        for (ParsedLongTerms.ParsedBucket bucket : buckets) {
            SearchResponseTmVo searchResponseTmVo = new SearchResponseTmVo();
            Long tmId = (Long)bucket.getKey();
            searchResponseTmVo.setTmId(tmId);
            ParsedStringTerms tmNameAgg = bucket.getAggregations().get("tmNameAgg");
            ParsedStringTerms tmLogoUrlAgg = bucket.getAggregations().get("tmLogoUrlAgg");
            List< ParsedStringTerms.ParsedBucket> tmNameAggbuckets = (List<ParsedStringTerms.ParsedBucket>) tmNameAgg.getBuckets();
            List< ParsedStringTerms.ParsedBucket> tmLogoUrlAggbuckets = (List<ParsedStringTerms.ParsedBucket>) tmLogoUrlAgg.getBuckets();
            for (ParsedStringTerms.ParsedBucket tmLogoUrlAggbucket : tmLogoUrlAggbuckets) {
                String tmLogoUrl = (String)tmLogoUrlAggbucket.getKey();
                searchResponseTmVo.setTmLogoUrl(tmLogoUrl);
            }
            for (ParsedStringTerms.ParsedBucket tmNameAggbucket : tmNameAggbuckets) {
                String tmName = (String)tmNameAggbucket.getKey();
                searchResponseTmVo.setTmName(tmName);
            }
            responseTmVos.add(searchResponseTmVo);

        }
        responseVo.setTrademarkList(responseTmVos);

        //解析平台属性聚合结果
        ParsedNested attrsAgg = searchResponse.getAggregations().get("attrsAgg");
        ParsedLongTerms attrIdAggTerms = attrsAgg.getAggregations().get("attrIdAgg");
        List<ParsedLongTerms.ParsedBucket> attrAggbuckets = (List<ParsedLongTerms.ParsedBucket>) attrIdAggTerms.getBuckets();
        List<SearchResponseAttrVo> responseAttrVos = new ArrayList<>();
        for (ParsedLongTerms.ParsedBucket attrAggbucket : attrAggbuckets) {
            SearchResponseAttrVo searchResponseAttrVo = new SearchResponseAttrVo();
            searchResponseAttrVo.setAttrId((Long) attrAggbucket.getKey());
            ParsedStringTerms  attrNameAggBuckets= attrAggbucket.getAggregations().get("attrNameAgg");
            List<ParsedStringTerms.ParsedBucket> attrNameAggBucket = (List<ParsedStringTerms.ParsedBucket>) attrNameAggBuckets.getBuckets();
            for (ParsedStringTerms.ParsedBucket parsedBucket : attrNameAggBucket) {
                searchResponseAttrVo.setAttrName((String)parsedBucket.getKey());
                ParsedStringTerms attrValueAgg = parsedBucket.getAggregations().get("attrValueAgg");
                List<ParsedStringTerms.ParsedBucket> attrValueAggBuckets = (List<ParsedStringTerms.ParsedBucket>) attrValueAgg.getBuckets();
                List<String> attrValueList = new ArrayList<>();
                for (ParsedStringTerms.ParsedBucket aggbucket : attrValueAggBuckets) {
                    String attrValue = (String)aggbucket.getKey();
                    attrValueList.add(attrValue);
                }
                searchResponseAttrVo.setAttrValueList(attrValueList);
            }
            responseAttrVos.add(searchResponseAttrVo);
        }

        responseVo.setAttrsList(responseAttrVos);
        long totalHits = hits.getTotalHits();
        responseVo.setTotal(totalHits);
        responseVo.setGoodsList(goodsList);
        return responseVo;
    }

    //构建查询条件
    private SearchRequest buildSearchRequest(SearchParam searchParam) {
        SearchRequest searchRequest = new SearchRequest("goods");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //创建组合对象
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //1.关键词搜索
        String keyword = searchParam.getKeyword();
        if(!StringUtils.isEmpty(keyword)){
            boolQueryBuilder.must(QueryBuilders.matchQuery("title",keyword).operator(Operator.AND));
        }else{
            boolQueryBuilder.must(QueryBuilders.matchAllQuery());
        }
        //2.过滤条件
        String trademark = searchParam.getTrademark();
        if(!StringUtils.isEmpty(trademark)){
            String[]  trademarks= trademark.split(":");
            boolQueryBuilder.must(QueryBuilders.termQuery("tmId",trademarks[0]));
        }
        //3.平台属性
        String[] paramProps = searchParam.getProps();
        if(paramProps!=null&&paramProps.length>0){
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            for (String paramProp : paramProps) {
                BoolQueryBuilder subBoolQuery = QueryBuilders.boolQuery();
                String[] p = paramProp.split(":");
                subBoolQuery.must(QueryBuilders.matchQuery("attrs.attrId",p[0]));
                subBoolQuery.must(QueryBuilders.matchQuery("attrs.attrValue",p[1]));
                queryBuilder.must(QueryBuilders.nestedQuery("attrs",subBoolQuery, ScoreMode.None));
            }
            boolQueryBuilder.filter(queryBuilder);
        }
        searchSourceBuilder.query(boolQueryBuilder);
        String order = searchParam.getOrder();
        if(!StringUtils.isEmpty(order)){
            String[] orders = order.split(":");
            if(order!=null){
                String orderStr = "";
                switch (orders[0]){
                    case "1" :
                        orderStr ="hotScore";
                        break;
                    case "2":
                        orderStr = "price";
                        break;
                }
                System.out.println(orderStr);
                System.out.println(orders[1]);
                searchSourceBuilder.sort(orderStr,orders[1].equalsIgnoreCase("asc")?SortOrder.ASC:SortOrder.DESC);
            }

        }
        Integer pageNo = searchParam.getPageNo();
        Integer pageSize = searchParam.getPageSize();
        searchSourceBuilder.from((pageNo-1)*pageSize);
        searchSourceBuilder.size(pageSize);
        searchRequest.source(searchSourceBuilder);
        //6.高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title").preTags("<font style='color : red'>").postTags("</font>");
        searchSourceBuilder.highlighter(highlightBuilder);
        //7.品牌聚合
        searchSourceBuilder.aggregation(
                AggregationBuilders.terms("tmIdAgg").field("tmId").
                subAggregation(AggregationBuilders.terms("tmNameAgg").field("tmName")).
                subAggregation(AggregationBuilders.terms("tmLogoUrlAgg").field("tmLogoUrl")));
        //8.平台属性聚合
        searchSourceBuilder.aggregation(AggregationBuilders.nested("attrsAgg","attrs")
                .subAggregation(AggregationBuilders.terms("attrIdAgg").field("attrs.attrId")
                .subAggregation(AggregationBuilders.terms("attrNameAgg").field("attrs.attrName")
                 .subAggregation(AggregationBuilders.terms("attrValueAgg").field("attrs.attrValue")))));
        System.out.println(searchSourceBuilder.toString());
        return searchRequest;

    }
}
